// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blaster/PlayerState/BlasterPlayerState.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/PlayerState.h"
#include "BlasterPlayerController.generated.h"

class ABlasterHUD;
class UCharacterOverlay;
class ABlasterGameMode;
class ABlasterPlayerState;
class ABlasterGameState;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FHighPingDelegate, bool, bPingTooHigh);

/**
 * 
 */
UCLASS()
class BLASTER_API ABlasterPlayerController : public APlayerController
{
	GENERATED_BODY()
public:
	void SetHUDHealth(float Health, float MaxHealth);
	void SetHUDShield(float Shield, float MaxShield);
	void SetHUDScore(float Score);
	void SetHUDDefeats(int32 Defeats);
	void SetHUDWeaponAmmo(int32 Ammo);
	void SetHUDCarriedAmmo(int32 Ammo);
	void SetHUDMatchCountDown(float CountdownTime);
	void SetHUDAnnouncementCountdown(float CountdownTime);
	void SetHUDGrenades(int32 Grenades);
	//当控制器拥有Pawn时，才执行的函数
	virtual void OnPossess(APawn* aPawn) override;
	virtual void Tick(float DeltaTime) override;
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

	void HideTeamSocres();
	void InitTeamScores();
	void SetHUDRedTeamScore(int32 RedSocre);
	void SetHUDBlueTeamScore(int32 BlueSocre);
	
	virtual float GetServerTime(); //返回服务器上的世界时间秒数
	//ReceivedPlayer：当调用玩家控制器的窗口或网络连接与玩家控制器相关联时调用
	virtual void ReceivedPlayer() override;
	void OnMatchStateSet(FName State, bool bTeamsMatch = false);
	void HandleMatchHasStarted(bool bTeamsMatch = false);
	void HandleCooldown();

	float SingleTripTime = 0.f;

	FHighPingDelegate HighPingDelegate;
	//不希望每一个玩家向所有玩家广播，我们希望的是玩家自己向自己广播，另外也希望是从服务器上开始执行，因此利用从服务器上调用客户端RPC的方式实现
	void BroadcastElim(APlayerState* Attacker, APlayerState* Victim);
protected:
	virtual void BeginPlay() override;
	void SetHUDTime();
	void PollInit();
	//控制器设置自定义输入绑定
	virtual void SetupInputComponent() override;
	//在服务器上执行的函数，请求服务器的世界时间秒数
	UFUNCTION(Server, Reliable)
	void ServerRequestServerTime(float TimeOfClientRequest);
	//在客户端上执行的函数，响应服务器时间包括客户端请求世界时间秒数和服务器回复客户端请求的世界时间秒数
	UFUNCTION(Client, Reliable)
	void ClientReportServerTime(float TimeOfClientRequest, float TimeServerReceivedClientRequest);

	float ClientServerDelta{0.f};
	UPROPERTY(EditAnywhere, Category="Time")
	float TimeSyncFrequency{5.f};
	float TimeSyncRunningTime{0.f};
	void CheckTimeSync(float DeltaTime);
	UFUNCTION(Server, Reliable)
	void ServerCheckMatchState();
	UFUNCTION(Client, Reliable)
	void ClientJoinMidgame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime);
	void HighPingWarning();
	void StopHighPingWarning();
	void CheckPing(float DeltaTime);

	void ShowReturnToMainMenu();

	UFUNCTION(Client, Reliable)
	void ClientElimAmmouncement(APlayerState* Attacker, APlayerState* Victim);
	UPROPERTY(ReplicatedUsing=OnRep_ShowTeamSocres)
	bool bShowTeamSocres{false};
	UFUNCTION()
	void OnRep_ShowTeamSocres();

	FString GetInfoText(const TArray<ABlasterPlayerState*>& Players);

	FString GetTeamsInfoText(ABlasterGameState* BlasterGameState);
private:
	UPROPERTY()
	ABlasterHUD* BlasterHUD;
	UPROPERTY(EditAnywhere, Category = "HUD")
	TSubclassOf<class UUserWidget> ReturnToMainMenuWidget;
	UPROPERTY()
	class UReturnToMainMenu* ReturnToMainMenu;
	bool bReturnToMainMenuOpen{false};

	UPROPERTY()
	ABlasterGameMode* BlasterGameMode;
	float MatchTime{0.f};
	float WarmupTime{0.f};
	uint32 CountDownInt{0};
	float LevelStartingTime{0.f};
	float CooldownTime{0.f};
	UPROPERTY(ReplicatedUsing=OnRep_MatchState)
	FName MatchState;
	UFUNCTION()
	void OnRep_MatchState();
	UPROPERTY()
	UCharacterOverlay* CharacterOverlay;
	bool bInitializeCharacterOverlay{false};
	float HUDHealth;
	bool bInitializeHealth{false};
	float HUDMaxHealth;
	float HUDShield;
	bool bInitializeShield{false};
	float HUDMaxShield;
	float HUDScore;
	bool bInitializeScore{false};
	int32 HUDDefeats;
	bool bInitializeDefeats{false};
	int32 HUDGrenades;
	bool bInitializeGrenades{false};
	float HUDCarriedAmmo;
	bool bInitializeCarriedAmmo{false};
	float HUDWeaponAmmo;
	bool bInitializeWeaponAmmo{false};


	float HighPingRunningTime{0.f};
	UPROPERTY(EditAnywhere)
	float HighPingDuration{5.f};
	float PingAnimationRunningTime{0.f};
	UPROPERTY(EditAnywhere)
	float CheckPingFrequency{20.f};
	UFUNCTION(Server, Reliable)
	void ServerReportPingStatus(bool bHighPing);

	UPROPERTY(EditAnywhere)
	float HighPingThreshold{50.f};
};
